/*SPWGIF, Signal Processing Web Graphic Interface Framework
    Copyright (C) 2015  Dimitar Nikolov

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
	
	You could contact me by email at dnikolov.co.nf@gmail.com
	For a copy of the GPL v3 check also at dnikolov.co.nf/html/gplv3.html
*/
var SPWGIF = function (params) {
	var that = this;
	var debug = (params && params.debug)? params.debug : false;	
	function create(proto){
		var NewObj = function(){};
		NewObj.prototype = proto;
		return new NewObj;
	}
	function dprint(message){
		if(debug==true){
			console.info(message);
		}
	}
	function clone(from,to){
		for (var key in from){
			if(from.hasOwnProperty(key)){
				if( (typeof from[key]) === "object"){
					to[key] = {};
					clone(from[key], to[key]);
				}else{
					to[key]=from[key];
				}
			}
		}
		return to;
	}
	
	var tools = new function(){
		var getCurrentURL = function(){
			return document.URL.toString().toLowerCase();
		};
		var getCurrentRelativePathToRessources = function(){
			var url = getCurrentURL();
			url = url.match(/(http:\/\/[A-Za-z0-9_-]*(\.[A-Za-z0-9_-]*)*)\/(.*[\|\/])*/,"../")[3];
			return url.replace(/(.*\/)*/g,"../");
		}
		var getRelativeToElementCoordinates = function(event,element){
			var totalOffsetX = 0;
			var totalOffsetY = 0;
			var relativeX = 0;
			var relativeY = 0;
			var currentElement = element;
			do{
				totalOffsetX += currentElement.offsetLeft - currentElement.scrollLeft;
				totalOffsetY += currentElement.offsetTop - currentElement.scrollTop;
			}
			while(currentElement = currentElement.offsetParent)
			relativeX =  event.pageX-totalOffsetX;
			relativeY =  event.pageY-totalOffsetY;
			return {x:relativeX, y:relativeY};
		};
		var getRelativeToElementCenterCoordinates = function(coordinatesRelativeToElement,constraints){
			var coordinatesRelativeToElementCenter = {x:undefined,y:undefined};
			if(typeof constraints == 'object' ){
				coordinatesRelativeToElementCenter.x = coordinatesRelativeToElement.x - constraints.x;
				coordinatesRelativeToElementCenter.y = constraints.y - coordinatesRelativeToElement.y;
			}else{
				coordinatesRelativeToElementCenter.x = coordinatesRelativeToElement.x - constraints;
				coordinatesRelativeToElementCenter.y = constraints - coordinatesRelativeToElement.y;
			}
			return coordinatesRelativeToElementCenter;
		}
		var isArray = function(toCheck){
		   return(Object.prototype.toString.call( toCheck ) === '[object Array]');
		}
		this.getRelativeToElementCenterCoordinates = getRelativeToElementCenterCoordinates;
		this.getRelativeToElementCoordinates = getRelativeToElementCoordinates;
		this.getCurrentRelativePathToRessources = getCurrentRelativePathToRessources;
		this.create = create;
		this.isArray = isArray;
	};
	
	var ComponentManager = function(){
		var that = this;
		var CM = this;
		var defaultComponents = {
			panel:{
				drawPanel:function(){
					var container = document.getElementById(this.containerID);
					var container = document.getElementById(this.containerID);
					var newComponent;
					this.HTMLBase="<div id="+this.id+" >&nbsp;</div>";
					var defaultCss = 'position:absolute;\
									background:#D2D1D1;\
									background:\
										repeating-linear-gradient(\
										30deg,rgba(210, 209, 209,1),\
										rgba(128,128,128,0.1) 10%,\
										rgba(128,128,128,0.8) 40%,\
										rgba(210, 209, 209,1) 60%),\
										repeating-linear-gradient(\
										-90deg,rgba(210, 209, 209,1),\
										rgba(128,128,128,0.1) 10%,\
										rgba(128,128,128,0.8) 40%,\
										rgba(210, 209, 209,1) 60%);\
									background-size:100%;\
									background-repeat:no-repeat,no-repeat;\
									min-width:10px;min-height:10px;\
									-webkit-user-select:none;\
									-khtml-sser-select:none;\
									-moz-user-select:none;\
									-ms-user-select:none;,\
									user-select:none;\
									touch-callout:none;\
									';
					container.innerHTML+=this.HTMLBase;
					newComponent = document.getElementById(this.id);
					newComponent.style.cssText+=defaultCss;
					var supportedCSSRules = this.getSupportedCSSRules();
					for (var ruleIndex in supportedCSSRules ){
						if(this.drawParams[supportedCSSRules[ruleIndex]]){
							newComponent.style.cssText+=(supportedCSSRules[ruleIndex]+':'
														+this.drawParams[supportedCSSRules[ruleIndex]]+';');
						}
					}
					return newComponent;
				},
				drawParams:{
					width:"200px",
					height:"200px",
					top:undefined,
					bottom:undefined,
					left:undefined,
					right:undefined
				},
				controlInterfaceBuilder:function(){
					var that = this;
					var getChilds = function(){
						return that.childs;
					}
					return {
						getChilds:getChilds
					}
				}
			},
			knob:{
				drawKnob:function(){
					var that = this;
					var container = document.getElementById(this.containerID);
					var newComponent;
					var widthUnits;
					var baseHeight,helperElement;var knob;
					var getDistributedScaleNumbersAsSpans = function(scaleParametersObject){
						var scaleParameters = scaleParametersObject;
						var scaleNumbers="";
						var toRadianCoefficent = Math.PI/180;
						var localEmphase=0;
						var fontSize =1.3-(scaleParameters.divisions)/(scaleParameters.divisions+10);
						if(!scaleParameters.phase||scaleParameters.phase<0)scaleParameters.phase=0;
						for(var i=scaleParameters.phase;i<scaleParameters.divisions;i++){
							var actualTop;var actualLeft;
							var currentDivision;
							var currentFontSize = fontSize;
							var currentOutCoefficent = scaleParameters.outCoefficent;
							if(scaleParameters.alternate==true){
								if(i%2==0){
									currentOutCoefficent = scaleParameters.outCoefficent*0.9;
								}else{
									currentOutCoefficent = scaleParameters.outCoefficent*1;
								}
							}
							var relativeToCenterTop = Math.sin( (90-i*scaleParameters.Q)*toRadianCoefficent)*scaleParameters.radius*currentOutCoefficent;
							var relativeToCenterLeft = Math.cos( (90-i*scaleParameters.Q)*toRadianCoefficent)*scaleParameters.radius*currentOutCoefficent;
							var marginLeft = Math.floor(i/10) == 0 ? -( Math.floor(i/10)+1 )/2 : -( Math.floor(i/10))/2;
							actualTop = ( relativeToCenterTop>=0 ) ? scaleParameters.radius - relativeToCenterTop:scaleParameters.radius+(-relativeToCenterTop);
							actualTop+=scaleParameters.yCorrection;
							actualLeft = ( relativeToCenterLeft>=0 ) ? scaleParameters.radius+relativeToCenterLeft : scaleParameters.radius+relativeToCenterLeft;
							if(localEmphase%scaleParameters.emphase==0){
								currentFontSize = (scaleParameters.alternate==true) ? fontSize*1.2 : fontSize*1.6;
							}
							localEmphase++;
							scaleNumbers += "<span  id='"+that.id+"_scaleNumber"+i+"' style=\"position:absolute;top:"+actualTop+"px;left:"+actualLeft+"px;\
								font-weight:bold;font-size:"+currentFontSize+"em;margin-left:"+marginLeft+"em;\">"+(i*scaleParameters.divisionStep)+"</span>";
						}
						return scaleNumbers;
					};
					var prepareScaleDivisions = function(divisions,divisionStep,diameter,emphase){
						var scaleNumbers="";
						var radius = parseInt(diameter)/2;
						if(!divisionStep||divisionStep<=0)divisionStep=1;
						var scaleParameters = {
							Q:360/divisions,
							divisions:divisions,
							divisionStep:divisionStep,
							phase:0,
							emphase:emphase,
							radius:radius,
							yCorrection:-0.11*radius,
							outCoefficent:0.73,
							alternate:false
						};
						scaleNumbers = getDistributedScaleNumbersAsSpans(scaleParameters);
						return scaleNumbers;
					}
					var scaleNumbers="";
					this.HTMLBase ='\
						<div id="'+this.id+'">\
							<div id="'+this.id+'_knobSocket" >\
								<div id="'+this.id+'_knobScale" >'
									+scaleNumbers+
									'<div id="'+this.id+'_actualKnob" >\
										<div id="'+this.id+'_knobTop">\
											<div id="'+this.id+'_knobIndicator">\
											</div>\
										</div>\
									</div>\
								</div>\
							</div>\
						</div>';
					var defaultKnobCSS ='\
							position: absolute;\
							-webkit-user-select:none;\
							-khtml-sser-select:none;\
							-moz-user-select:none;\
							-ms-user-select:none;,\
							user-select:none;\
							touch-callout:none;\
						';
					var defaultKnobSocketCSS='\
												position:absolute;\
												width:100%;height:100%;\
											';
					var defaultKnobScaleCSS='\
											position:absolute;\
											width:100%;\
											height:100%;\
											border-radius: 100%;\
											background-color: #CFCFCF;\
											background: -webkit-repeating-linear-gradient(30deg,\
													rgba(210, 209, 209,1), \
													rgba(128,128,128,0.1) 10%,\
													rgba(128,128,128,0.8) 40%,\
													rgba(210, 209, 209,1) 60%);\
											border: 1px solid black;\
											box-shadow: 0px 1px 0px 1px #202020;\
											';
					var defaultActualKnobCSS='position:absolute;\
											box-sizing: content-box;\
											top:50%;\
											left:50%;\
											height: 50%;\
											width: 50%;\
											margin-top: -30%;\
											margin-left: -25%;\
											background-color: #CFD4D9;\
											background:	-webkit-repeating-radial-gradient(\
												circle,  rgba(200,200,200, 1) 2px, rgba(163, 163, 163, 1) 2px,\
												 rgba(163, 163, 163, 1) 4px, rgba(200,200,200, 1) 6px, rgba(200,200,200, 1) 6px),\
												-webkit-repeating-linear-gradient(30deg,\
													rgba(210, 209, 209,1), \
													rgba(128,128,128,0.1) 10%,\
													rgba(128,128,128,0.8) 40%,\
													rgba(210, 209, 209,1) 60%);\
											cursor:pointer;\
											border-bottom: 6px solid #bbb;\
											box-shadow: 0px 2px 0px 1px #6C6E71, 0px 5px 1px 1px black,0px 9px 2px 4px rgba(26, 26, 26,0.7);\
											border: 1px solid #333;\
											border-radius: 100%;\
											';
					var defaultKnobTopCSS='	position:absolute;\
												width:100%;\
												height:100%;\
												';
					var defaultKnobIndicatorCSS='\
												position:absolute;\
												top:50%;\
												left:50%;\
												margin-top: -43%;\
												margin-left: -5%;\
												height: 10%;\
												width: 10%;\
												border-radius: 100%;\
												background-color: #21BB21;\
												background: radial-gradient(#2BFD2B 10%,#1EB41E  55%, #30B530 80% , green);\
												box-shadow: 0px 0px 2px 1px #22C922;\
												';
					helperElement = document.createElement('div');
					helperElement.innerHTML=this.HTMLBase;
					knob = container.appendChild(helperElement.children[0]);
					newComponent = document.getElementById(this.id);
					newComponent.style.cssText=defaultKnobCSS;
					var supportedCSSRules = this.getSupportedCSSRules();
					for (var ruleIndex in supportedCSSRules ){
						if(this.drawParams[supportedCSSRules[ruleIndex]]){
							newComponent.style.cssText+=(supportedCSSRules[ruleIndex]+':'
														+this.drawParams[supportedCSSRules[ruleIndex]]+';');
						}
					}
					var knobSocket = document.getElementById(this.id+'_knobSocket');
					knobSocket.style.cssText=defaultKnobSocketCSS;
					var knobScale = document.getElementById(this.id+'_knobScale');
					knobScale.style.cssText=defaultKnobScaleCSS;
					var actualKnob = document.getElementById(this.id+'_actualKnob');
					actualKnob.style.cssText=defaultActualKnobCSS;
					var knobTop = document.getElementById(this.id+'_knobTop');
					knobTop.style.cssText=defaultKnobTopCSS;
					var knobIndicator = document.getElementById(this.id+'_knobIndicator');
					knobIndicator.style.cssText=defaultKnobIndicatorCSS;
					baseHeight = parseInt(newComponent.style.height);
					widthUnit = newComponent.style.height.match(/([A-Za-z%])*$/)[0];
					if(this.drawParams.display==true){
						knobSocket.style.cssText+='position:absolute;top:15%;left:7.5%;width:85%;height:85%;';
						CM.createComponent({
							type:"display",
							containerID:this.id,
							drawParams:{
								width:"40%",
								height:"13%",
								top:"0%",
								left:"30%"
							}
						});
					}
					knobSocket = document.getElementById(this.id+'_knobSocket');
					if(this.drawParams.label){
						knobSocket.style.cssText=defaultKnobSocketCSS+'position:absolute;top:15%;bottom:15%;left:15%;width:70%;height:70%;';
						CM.createComponent({
							type:"label",
							containerID:that.id,
							drawParams:{
								width:'100%',
								height:"13%",
								bottom:"0px",
								placeHolder:"bottom",
								content:that.drawParams.label
							}
						});
					}
					scaleNumbers = prepareScaleDivisions(
															this.drawParams.divisions,
															this.drawParams.divisionStep,
															baseHeight*0.70,
															this.drawParams.emphase
														);
					var helperElement = document.createElement("div");
					helperElement.innerHTML = scaleNumbers;
					var maxIdx = helperElement.children.length;
					for(var indx = 0;indx<helperElement.children.length;indx++){
						knobSocket.insertBefore(helperElement.children[indx].cloneNode(true),knobSocket.lastChild);
					}
					return newComponent;
				},
				drawParams:{
					width:"100px",
					height:"100px",
					top:undefined,
					bottom:undefined,
					divisions:10,
					divisionStep:1,
					emphase:undefined,
					label:undefined,
					display:undefined,
					placeHolder:undefined,
					decimalPlaces:2,
					left:undefined,
					right:undefined
				},
				controlInterfaceBuilder:function(){
					var that=this;
					var isOff=false;
					var isMouseDown=false;
					var coordinates;
					var lastAngle=0;
					var initialAngle=0;
					var radius = parseInt(document.getElementById(this.id+'_actualKnob').style.width)/2;
					radius = parseInt(window.getComputedStyle(document.getElementById(this.id+'_actualKnob')).width)/2;
					var Q = 360/(that.drawParams.divisions*that.drawParams.divisionStep);
					var lastCoordinatesRelativeToCenter={
						x:0,
						y:0
					};
					if(that.controlInterfaceParams.minTurnPosition){
						if(that.controlInterfaceParams.minTurnPosition<0){
							that.controlInterfaceParams.minTurnPosition=0;
						}
					}else{
						that.controlInterfaceParams.minTurnPosition=0;
					}
					if(that.controlInterfaceParams.maxTurnPosition){
						if(that.controlInterfaceParams.maxTurnPosition>(that.drawParams.divisions*that.drawParams.divisionStep)){
							that.controlInterfaceParams.maxTurnPosition=that.drawParams.divisions*that.drawParams.divisionStep;
						}
					}else{
						that.controlInterfaceParams.maxTurnPosition=that.drawParams.divisions*that.drawParams.divisionStep;
					}
					
					var currentValue=0;
					var getChilds = function(){
						var that = this;
						return that.childs;
					};
					var onMouseDown = function(event){
						isMouseDown=true;
						var coordinates = tools.getRelativeToElementCoordinates(event,this);
						var coordinatesRelativeToCenter = {x:undefined,y:undefined};
						coordinatesRelativeToCenter.x = coordinates.x < radius ?
													-(radius-coordinates.x) 
													: coordinates.x-radius;
						coordinatesRelativeToCenter.y = coordinates.y < radius ?
													radius-coordinates.y
													: -(coordinates.y-radius);
						hypotenusesLength = Math.sqrt(Math.pow(coordinatesRelativeToCenter.x,2)+Math.pow(coordinatesRelativeToCenter.y,2));
						if(coordinatesRelativeToCenter.y<0){
							initialAngle = -Math.acos(coordinatesRelativeToCenter.x/hypotenusesLength)*180/Math.PI;
						}else{
							initialAngle = Math.acos(coordinatesRelativeToCenter.x/hypotenusesLength)*180/Math.PI;
						}
						
					}
					var currentAngle;
					var onMouseMove = function(event){
						if(isMouseDown==false)return;
						if(lastAngle>360){
							lastAngle=360;
							return;
						}
						if(lastAngle<0){
							lastAngle=0;
							return;
						}
						var coordinatesRelativeToCenter={
							x:undefined,
							y:undefined
						};
						var isDeltaPositive=undefined;
						var deltaAngle;
						var hypotenusesLength;
						var toTurnTo;
						//currentValue=0;
						var coordinates = tools.getRelativeToElementCoordinates(event,this);
						currentAngle;
						coordinatesRelativeToCenter.x = coordinates.x < radius ?
													-(radius-coordinates.x) 
													: coordinates.x-radius;
						coordinatesRelativeToCenter.y = coordinates.y < radius ?
													radius-coordinates.y
													: -(coordinates.y-radius);
						hypotenusesLength = Math.sqrt(Math.pow(coordinatesRelativeToCenter.x,2)+Math.pow(coordinatesRelativeToCenter.y,2));
						if(coordinatesRelativeToCenter.y<0){
							currentAngle = -Math.acos(coordinatesRelativeToCenter.x/hypotenusesLength)*180/Math.PI;
						}else{
							currentAngle = Math.acos(coordinatesRelativeToCenter.x/hypotenusesLength)*180/Math.PI;
						}
						deltaAngle = -(currentAngle-initialAngle);
						toTurnTo = (lastAngle-deltaAngle)/Q;
						toTurnTo = toTurnTo.toFixed(that.drawParams.decimalPlaces);
						lastAngle=(lastAngle-deltaAngle);
						turnTo(toTurnTo);
					
					}
					var onMouseOut = function(){
						isMouseDown=false;
					}
					var onMouseUp = function(){
						isMouseDown=false;
					}
					document.getElementById(this.id+'_knobTop').addEventListener('mousemove',onMouseMove,false);
					document.getElementById(this.id+'_knobTop').addEventListener('mouseout',onMouseOut,false);
					document.getElementById(this.id+'_knobTop').addEventListener('mouseup',onMouseUp,false);
					document.getElementById(this.id+'_knobTop').addEventListener('mousedown',onMouseDown,false);
					
					var turnTo = function(value){
						if(value>that.controlInterfaceParams.maxTurnPosition){
							value=that.controlInterfaceParams.maxTurnPosition
						};
						if(value<that.controlInterfaceParams.minTurnPosition){
							value=that.controlInterfaceParams.minTurnPosition
						}
						var toTurnTo = Q*value;
						lastAngle = toTurnTo;
						var actualKnob = document.getElementById(that.id+'_knobTop');
						actualKnob.style.cssText +='-webkit-transform:rotate(0deg);';
						actualKnob.style.cssText +='-moz-transform:rotate(0deg);';
						actualKnob.style.cssText +='transform:rotate(0deg);';
						actualKnob.style.cssText +='-webkit-transform:rotate('+toTurnTo+'deg);';
						actualKnob.style.cssText +='-moz-transform:rotate('+toTurnTo+'deg);';
						actualKnob.style.cssText +='transform:rotate('+toTurnTo+'deg);';
						currentValue = value;
						if(that.drawParams.display==true){
							var displayElement;
							var elementsToParse = document.getElementById(that.id).children;
							
							for( var elementIdx =0;elementIdx<elementsToParse.length;elementIdx++){
								if(elementsToParse[elementIdx].id.match(/^[A-Za-z]*/)[0]=="display"){
									displayElement = elementsToParse[elementIdx];
								}
							}
							var displayComponent = CM.getComponent(displayElement.id);
							displayComponent.controlInterface.setValue(value);
						}
						if(typeof that.controlInterfaceParams.onTurn == 'function'&&!isOff){
							that.controlInterfaceParams.onTurn(value);
						}
						return that;
					};
					var on = function(){
						isOff = false;
						document.getElementById(that.id+'_knobInddicator').style.backgroundColor="#1EB41E";
						document.getElementById(that.id+'_knobInddicator').style.background=" radial-gradient(#2BFD2B 10%,#1EB41E  55%, #30B530 80% , green);";
						
					}
					var off = function(){
						isOff=true;
						document.getElementById(that.id+'_knobInddicator').style.backgroundColor="black";
						document.getElementById(that.id+'_knobInddicator').style.background="";
					}
					var getCurrentValue=function(){
						return currentValue;
					};
					return {
						getValue:getCurrentValue,
						getChilds:getChilds,
						turnTo:turnTo,
						off:off,
						on:on
					};
				},
				controlInterfaceParams:{
					onTurn:undefined,
					maxTurnPosition:undefined,
					minTurnPosition:undefined
				}
			},
			display:{
				drawDisplay:function(){
					var that=this;
					var container = document.getElementById(that.containerID);
					var newComponent,firstChild,helperElement,lastChild;
					var initialValue = 0;
					initialValue = initialValue.toFixed(that.drawParams.decimalPlaces);
					that.HTMLBase = '\
									<div id="'+that.id+'">\
										<div id="'+that.id+'_displaySocket" >\
											<div id="'+that.id+'_actualDisplay">'
											+initialValue+
											'</div>\
										</div>\
									</div>\
									';
					var defaultCSS = 'position:absolute;\
										width:100%;height:100%;';
					firstChild = container.firstChild;
					helperElement = document.createElement("div");
					helperElement.innerHTML = this.HTMLBase;
					newComponent=helperElement.children[0];
					if(this.drawParams.placeHolder=="top"){
						container.insertBefore(newComponent, firstChild);
					}else{
						container.appendChild(newComponent, firstChild);
					}
					helperElement=undefined;
					newComponent = document.getElementById(this.id);
					newComponent.style.cssText+=defaultCSS;
					var supportedCSSRules = this.getSupportedCSSRules();
					for (var ruleIndex in supportedCSSRules ){
						if(this.drawParams[supportedCSSRules[ruleIndex]]){
							newComponent.style.cssText+=(supportedCSSRules[ruleIndex]+':'
														+this.drawParams[supportedCSSRules[ruleIndex]]+';');
						}
					}
					document.getElementById(this.id+'_displaySocket').style.cssText+='\
																					position:absolute;\
																					height:100%;\
																					width:100%;\
																					font-size:0.8em;\
																					';
					document.getElementById(this.id+'_actualDisplay').style.cssText+='\
																					position:absolute;\
																					height:100%;\
																					width:100%;\
																					top:0px;\
																					bottom:0px;\
																					text-align:center;\
																					border: 1px solid black;\
																					background-color: #DBDFF3;\
																					background: \
																					repeating-linear-gradient(45deg, white, #DBDFF3);\
																					border-radius: 15% 15% 15% 15%;\
																					box-shadow: inset 0px 0px 4px 1px #A2A5B4,\
																					0px 1px 1px 1px #222524;\
																					font-weight: bold;\
																					';
					return newComponent;
				},
				drawParams:{
					width:"100px",
					height:"100px",
					top:undefined,
					bottom:undefined,
					left:undefined,
					right:undefined,
					divisions:10,
					divisionStep:1,
					emphase:undefined,
					label:undefined,
					display:undefined,
					placeHolder:undefined,
					decimalPlaces:undefined
				},
				controlInterfaceBuilder:function(){
					var that=this;
					var setValue = function(value){
						document.getElementById(that.id+'_actualDisplay').innerHTML=value;
						if(that.controlInterfaceParams&&typeof that.controlInterfaceParams.onChange == "function"){
							that.controlInterfaceParams.onChange(document.getElementById(that.id+'_actualDisplay').innerHTML);
						}
					}
					var on = function(){
						document.getElementById(that.id+'_actualDisplay').style.color="black";
					}
					var off = function(){
						document.getElementById(that.id+'_actualDisplay').style.color="none";
					}
					var getValue = function(){
						return document.getElementById(that.id+'_actualDisplay').innerHTML;
					}
					return{
						setValue:setValue,
						getValue:getValue,
						on:on,
						off:off
					}
				},
				controlInterfaceParams:{
					onChange:undefined
				}
			},
			label:{
				drawLabel:function(){
					var that = this;
					this.HTMLBase = '<div id="'+this.id+'">\
										<div id="'+this.id+'_actualLabel">\
											'+this.drawParams.content+'\
										</div>\
									</div>';
					var defaultLabelCSS ='\
										position:absolute;\
										display:table-cell;\
										';
					var defaultActualLabelCSS='\
											position: absolute;\
											display: table-cell;\
											text-align:center;\
											vertical-align:middle;\
											background-color: #CFCFCF;\
											background:-webkit-repeating-linear-gradient(30deg,\
													rgba(210, 209, 209,1), \
													rgba(128,128,128,0.1) 10%,\
													rgba(128,128,128,0.8) 40%,\
													rgba(210, 209, 209,1) 60%);\
											border: 1px solid black;\
											/*border-bottom: 1px solid black;\
											box-shadow: 0px 1px 0px 1px #202020;*/\
											box-shadow: 1px 1px 1px 0px #292929;\
											min-width:40px;\
											min-height: 10px;\
											width: 100%;\
											height: 100%;\
											font-size: 0.8em;\
											font-weight: bold;\
											';
					var container = document.getElementById(this.containerID);
					var helperElement = document.createElement('div');
					helperElement.innerHTML = this.HTMLBase;
					var label = helperElement.children[0];
					container.appendChild(helperElement.children[0]);
					var actualLabel = document.getElementById(this.id+'_actualLabel');
					if(that.drawParams.placeHolder==="bottom"){
						defaultLabelCSS+='bottom:0%;';
					}
					label.style.cssText+=defaultLabelCSS;
					var supportedCSSRules = that.getSupportedCSSRules();
					for (var ruleIndex in supportedCSSRules ){
						if(that.drawParams[supportedCSSRules[ruleIndex]]){
							label.style.cssText+=(supportedCSSRules[ruleIndex]+':'
														+that.drawParams[supportedCSSRules[ruleIndex]]+';');
						}
					}
					actualLabel.style.cssText+=defaultActualLabelCSS;
					return helperElement.children[0];
				},
				drawParams:{
					width:"100%",
					height:"100%",
					top:undefined,
					bottom:undefined,
					left:undefined,
					right:undefined,
					content:'&nbsp;',
					placeHolder:undefined
				},
				controlInterfaceBuilder:function(){
					var that = this;
					var getChilds = function(){
						return that.childs;
					};
					var getValue = function(){
						return document.getElementById(that.id+'_actualLabel').innerHTML;
					};
					var setValue = function(value){
						document.getElementById(this.id+'_actualLabel').innerHTML=value;
						if(typeof that.controlInterfaceParams.onChange == "function"){
							that.controlInterfaceParams.onChange(document.getElementById(that.id+'_actualLabel').innerHTML);
						}
					};
					return {
						getChilds: getChilds,
						getValue:getValue,
						setValue:setValue
					};
				},
				controlInterfaceParams:{
					onChange:undefined
				}
			},
			slider:{
				drawSlider:function(){
					var that=this;
					var scaleNumbers;
					that.HTMLBase = '<div id="'+that.id+'">\
										<div id="'+that.id+'_sliderSocket">\
											<div id="'+that.id+'_sliderScale">\
												<div id="'+that.id+'_sliderSlot">\
													<div id="'+that.id+'_actualSlider">\
														<div id="'+that.id+'_sliderTop">\
															<div id="'+that.id+'_sliderIndicator">\
															</div>\
														</div>\
													</div>\
												</div>\
											</div>\
										</div>\
									</div>';
					var defaultSliderCSS='position:absolute;\
											-webkit-user-select:none;\
											-khtml-sser-select:none;\
											-moz-user-select:none;\
											-ms-user-select:none;,\
											user-select:none;\
											touch-callout:none;\
										';
					var defaultSliderSocketCSS='position:absolute;\
												width:100%;\
												height:100%;\
												';
					var defaultSliderScaleCSS='position:absolute;\
												width:100%;height:100%;\
												background-color: #CFCFCF;\
												background: -webkit-repeating-linear-gradient(30deg,\
													rgba(210, 209, 209,1), \
													rgba(128,128,128,0.1) 10%,\
													rgba(128,128,128,0.8) 40%,\
													rgba(210, 209, 209,1) 60%);\
												/*border: 1px solid black;*/\
												box-shadow: 0px 0px 1px 1px #292929;\
												';
					var defaultSliderSlotCSS='position:absolute;\
											box-sizing:content-box;\
											top:5%;\
											bottom:5%;\
											width:2%;\
											left:25%;\
											margin-left:-1%;\
											border:1px solid black;\
											background-color:black;\
											box-shadow: 0px 0px 3px 1px #232323 inset, 0px 0px 2px 1px #202020;\
											';
					var defaultActualSliderCSS='position:absolute;\
												box-sizing:content-box;\
												z-index:3;\
												width:2000%;\
												left:-1000%;\
												height:16.67%;\
												bottom:-8.3%;\
												background-color: #CFD4D9;\
												background:	\
													-webkit-repeating-linear-gradient(\
														90deg,  rgba(200,200,200, 0.3) 2px, rgba(163, 163, 163, 0.3) 2px,\
														rgba(163, 163, 163, 1) 4px, rgba(200,200,200, 1) 6px, rgba(200,200,200, 1) 6px),\
													-webkit-repeating-linear-gradient(30deg,\
														rgba(210, 209, 209,1)10%, \
														rgba(128,128,128,1) 20%,\
														rgba(128,128,128,1) 20%,\
														rgba(210, 209, 209,1) 30%);\
												border-radius:20%;\
												border-bottom:1px solid black;\
												box-shadow:\
													1px 1px 1px 0px #292929,\
													1px 2px 2px 1px gray,\
													1px 2px 1px 0px rgba(41,41,41,0.5);\
												cursor:pointer;\
												';
					var defaultSliderTopCSS='position:absolute;\
											width:100%;\
											height:14%;\
											top:43%;\
											background-color:rgba(32,32,32,1);\
											';
					var defaultSliderIndicatorCSS = '\
												position:absolute;\
												width:28.57%;\
												height:100%;\
												background-color: #21BB21;\
												background: radial-gradient(#2BFD2B 10%,#1EB41E  55%, #30B530 80% , green);\
												box-shadow: 0px 0px 2px 1px #22C922;\
												right:0%;\
												';
					var prepareSliderScaleNumbers = function(params){
						var scaleNumbers="";
						var offset = parseInt(params.offset)||0;
						var restOfHeight = 100-2*offset;
						var centerSpacing = restOfHeight/(params.divisions-1);
						var value;
						var fontSize = 100-30/centerSpacing;
						for(var i = 0;i<params.divisions;i++){
							value = i*params.divisionStep;
							value = value.toFixed(that.drawParams.decimalPlaces);
							scaleNumbers+='<span id="'+that.id+'_scaleNumber'+i+'" style="position:absolute;bottom:'+(offset/2+centerSpacing*i)+'%;\
											right:25%;font-weight:bold;font-size:'+fontSize+'%;margin-right:-12.5%;">'
											+value+
										'</span>';
						}
						return scaleNumbers;
					}
					var scaleParams = create(that.drawParams);
					scaleParams.offset=5;
					scaleNumbers = prepareSliderScaleNumbers(scaleParams);
					var container = document.getElementById(that.containerID);
					var helperElement = document.createElement('div');
					helperElement.innerHTML = that.HTMLBase;
					container.appendChild(helperElement.children[0]);
					var newComponent = document.getElementById(that.id);
					var sliderScale = document.getElementById(that.id+'_sliderScale');
					newComponent.style.cssText+=defaultSliderCSS;
					var supportedCSSRules = that.getSupportedCSSRules();
					for (var ruleIndex in supportedCSSRules ){
						if(this.drawParams[supportedCSSRules[ruleIndex]]){
							newComponent.style.cssText+=(supportedCSSRules[ruleIndex]+':'
														+that.drawParams[supportedCSSRules[ruleIndex]]+';');
						}
					}
					document.getElementById(that.id+'_sliderSocket').style.cssText+=defaultSliderSocketCSS;
					sliderScale.style.cssText+=defaultSliderScaleCSS;
					document.getElementById(that.id+'_sliderSlot').style.cssText+=defaultSliderSlotCSS;
					document.getElementById(that.id+'_actualSlider').style.cssText+=defaultActualSliderCSS;
					document.getElementById(that.id+'_sliderTop').style.cssText+=defaultSliderTopCSS;
					document.getElementById(that.id+'_sliderIndicator').style.cssText+=defaultSliderIndicatorCSS;
					(function(elementsToAddAsString){
						helperElement = document.createElement('div');
						helperElement.innerHTML = elementsToAddAsString;
						var elementsToAdd = helperElement.children;
						for(var i = 0;i<elementsToAdd.length;i++){
							sliderScale.appendChild(elementsToAdd[i].cloneNode(true));
						}
					})(scaleNumbers);
					var baseHeight = parseInt(document.getElementById(that.id).style.height);
					if(that.drawParams.display==true){
						var slider = document.getElementById(that.id);
						var sliderSocket = document.getElementById(that.id+'_sliderSocket');
						sliderSocket.style.cssText+='top:'+(0.14*baseHeight)+'px;height:85%;';
						CM.createComponent({
							type:'display',
							containerID:that.id,
							drawParams:{
								width:"90%",
								height:"11%",
								placeHolder:"top",
								top:"0%",
								left:"3%",
								decimalPlaces:that.drawParams.decimalPlaces
							}
						});
					}
					
					if(that.drawParams.label){
						var slider = document.getElementById(that.id);
						var sliderSocket = document.getElementById(that.id+'_sliderSocket');
						sliderSocket.style.cssText+='bottom:'+(0.14*baseHeight)+'px;height:'+baseHeight*0.70+'px;';
						CM.createComponent({
							type:'label',
							containerID:that.id,
							drawParams:{
								height:"12%",
								content:that.drawParams.label,
								placeHolder:"bottom"
							}
						});
					}
					return newComponent;
				},
				drawParams:{
					width:"10px",
					height:"10px",
					top:undefined,
					left:undefined,
					right:undefined,
					bottom:undefined,
					divisions:10,
					divisionStep:1,
					emphase:undefined,
					label:undefined,
					display:undefined,
					placeHolder:undefined,
					decimalPlaces:2
				},
				controlInterfaceBuilder:function(){
					var that = this;
					var isOff=false;
					var baseIndicatorBackground;
					var offset = 5;
					var restOfHeight = 100-2*offset;
					var centerSpacing = restOfHeight/(that.drawParams.divisions-1);
					var display;
					if(!that.controlInterfaceParams.maxSlidePosition){
						that.controlInterfaceParams.maxSlidePosition = (that.drawParams.divisions-1)*that.drawParams.divisionStep;
					}
					if(that.drawParams.display){
						var component = CM.getComponent(that.id);
						var childs = CM.getComponent(that.id).childs;
						var displayID;
						
						for (var i = 0;i<childs.length;i++){
							if(childs[i].match(/display.*/)){
								displayID = childs[i];
							}
						}
						display = document.getElementById(displayID+'_actualDisplay');
						baseIndicatorBackground = display.style.background;
					}
					var getChilds = function(){
						return that.childs;
					}
					var getValue = function(){
						return currentValue;
					}
					var getState = function(){
						return !isOff ? 'on' : 'off';
					}
					var on = function(){
						if(that.drawParams.display){
							var childs = CM.getComponent(that.id).childs;
							var displayID;
							var display;
							for (var i = 0;i<childs.length;i++){
								if(childs[i].match(/display.*/)){
									displayID = childs[i];
								}
							}
							display = document.getElementById(displayID+'_actualDisplay');
							display.style.background=baseIndicatorBackground;
						}
						isOff=false;
					}
					var off = function(){
						if(that.drawParams.display){
							var childs = CM.getComponent(that.id).childs;
							var displayID;
							var display;
							for (var i = 0;i<childs.length;i++){
								if(childs[i].match(/display.*/)){
									displayID = childs[i];
								}
							}
							display = document.getElementById(displayID+'_actualDisplay');
							display.style.background="black";
						}
						isOff=true;
					}
					var slideTo = function(val){
						if(isNaN(val))return;
						if(val>that.controlInterfaceParams.maxSlidePosition){
							val = that.controlInterfaceParams.maxSlidePosition.toFixed(that.drawParams.decimalPlaces);
						}
						if(val<that.controlInterfaceParams.minSlidePosition){
							val = that.controlInterfaceParams.minSlidePosition.toFixed(that.drawParams.decimalPlaces);
						}
						if(val>(that.drawParams.divisions-1)*that.drawParams.divisionStep){
							val = (that.drawParams.divisions-1)*that.drawParams.divisionStep;
						}
						if(val<0){
							val=0;
						}
						val = parseFloat(val).toFixed(that.drawParams.decimalPlaces);
						var scalesFromBottom = ( val/that.drawParams.divisionStep ).toFixed(that.drawParams.decimalPlaces) || 0;
						var actualSlider = document.getElementById(that.id+'_actualSlider');
						var heightOfSliderSlotInPx = parseFloat(window.getComputedStyle(document.getElementById(that.id+'_sliderSlot')).height);
						var centerSpacingInPercents = (100/heightOfSliderSlotInPx)*(heightOfSliderSlotInPx/(that.drawParams.divisions-1));
						centerSpacing = centerSpacingInPercents.toFixed(2);
						actualSlider.style.bottom=(parseInt('-8.3%')+centerSpacingInPercents*scalesFromBottom)+'%';
						if(that.drawParams.display){
							var childs = CM.getComponent(that.id).controlInterface.getChilds();
							var displayID;
							for (var i = 0;i<childs.length;i++){
								if(childs[i].match(/display.*/)){
									displayID = childs[i];
								}
							}
							var display = CM.getComponent(displayID);
							display.controlInterface.setValue(val);
						}
						currentValue = val;
						if(!isOff && typeof that.controlInterfaceParams.onChange == 'function'){
							that.controlInterfaceParams.onChange(val);
						}
						return that;
					}
					
					var initialYPosition=0;
					var deltaYPosition=0;
					var lastYPosition=0;
					var isMouseDown=false;
					var currentValue=0;
					var lastValue=0;
					var onMouseDown = function(event){
						isMouseDown = true;
						var widthRadius = parseInt(window.getComputedStyle(document.getElementById(this.id)).width)/2;
						var heightRadius = parseInt(window.getComputedStyle(document.getElementById(this.id)).height)/2;
						initialYPosition = tools.getRelativeToElementCenterCoordinates(
							tools.getRelativeToElementCoordinates(event,this),{x:widthRadius,y:heightRadius}
						).y;
					}
					var onMove = function(event){
						if(!isMouseDown)return;
						var element = document.getElementById(this.id);
						var radius = parseInt(window.getComputedStyle(document.getElementById(this.id)).width)/2;
						var radiusHeight = parseInt(window.getComputedStyle(document.getElementById(this.id)).height)/2;
						var constraints = {x:radius,y:radiusHeight};
						var heightOfSliderSocket = parseInt(window.getComputedStyle(document.getElementById(that.id)).height);
						var scalesToSlide=0;
						var relativeToElementCoordinates = tools.getRelativeToElementCoordinates(event,element);
						var relativeToElementCenterCoordintes = tools.getRelativeToElementCenterCoordinates(
							relativeToElementCoordinates
							,constraints
						);
						deltaYPosition = relativeToElementCenterCoordintes.y - initialYPosition;
						if(Math.abs(deltaYPosition)>radiusHeight*0.5){
							var helperValue;
							if(deltaYPosition>0){
								helperValue  = parseFloat(currentValue)+1*that.drawParams.divisionStep; 
								slideTo( parseFloat(helperValue).toFixed(that.drawParams.decimalPlaces));
							}
							if(deltaYPosition<0){
								helperValue  = parseFloat(currentValue)-1*that.drawParams.divisionStep; 
								slideTo(parseFloat(helperValue).toFixed(that.drawParams.decimalPlaces));
							}
						}
					}
					var onMouseOut = function(event){
						if(!event.fromElement)event.fromElement={};
						if(!event.toElement)event.toElement={};
						if( (event.fromElement.id==that.id+'_actualSlider' && event.toElement.id==that.id+'_sliderTop')
							|| (event.fromElement.id==that.id+'_sliderTop' && event.toElement.id==that.id+'_actualSlider')  )return;
						isMouseDown = false;
					}
					var onMouseUp = function(event){
						isMouseDown = false;
					}
					document.getElementById(that.id+'_actualSlider').addEventListener('mousedown',onMouseDown,false);
					document.getElementById(that.id+'_actualSlider').addEventListener('mouseup',onMouseUp,false);
					document.getElementById(that.id+'_actualSlider').addEventListener('mouseout',onMouseOut,false);
					document.getElementById(that.id+'_actualSlider').addEventListener('mousemove',onMove,false);
					return {
						getState:getState,
						getChilds:getChilds,
						slideTo:slideTo,
						getValue:getValue,
						on:on,
						off:off
					};
				},
				controlInterfaceParams:{
					onChange:undefined,
					maxSlidePosition:undefined,
					minSlidePosition:0
				}
			},
			button:{
				drawButton:function(){
					var that = this;
					that.HTMLBase = '<div id="'+that.id+'">\
										<div id="'+that.id+'_actualButton">\
											<div id="'+that.id+'_buttonTop">\
												<div id="'+that.id+'_buttonIndicator">\
												</div>\
												<span id="'+that.id+'_buttonLabel">'
													+that.drawParams.label+
												'</span>\
											</div>\
										</div>\
									</div>';
					var defaultButtonCSS = 'position:absolute;\
											min-height:20px;\
											min-width:30px;';
					var defaultActualButtonCSS = 'position:absolute;\
												background-color: #CFD4D9;\
												background:\
													-webkit-repeating-linear-gradient(\
														90deg,  rgba(200,200,200, 0.3) 2px, rgba(163, 163, 163, 0.3) 2px,\
														rgba(163, 163, 163, 1) 4px, rgba(200,200,200, 1) 6px, rgba(200,200,200, 1) 6px),\
													-webkit-repeating-linear-gradient(30deg,\
														rgba(210, 209, 209,1)10%, \
														rgba(128,128,128,1) 20%,\
														rgba(128,128,128,1) 20%,\
														rgba(210, 209, 209,1) 30%);\
												cursor:pointer;\
												border: 1px solid #333;\
												box-shadow: \
													1px 1px 1px 0px #292929,\
													1px 2px 1px 0px rgba(41,41,41,0.5);\
												min-width:40px;\
												min-height: 10px;\
												width: 100%;\
												height: 100%;\
												font-size: 0.8em;\
												font-weight: bold;';
					var defaultButtonTopCSS = '\
											position:absolute;\
											display:table-cell;\
											vertical-align:middle;\
											text-align:middle;\
											width:100%;\
											height:100%;\
											';
					var defaultButtonIndicatorCSS = 'position:absolute;\
											left:3%;\
											top:50%;\
											margin-top:-10px;\
											width:20px;\
											height:20px;\
											border-radius:100%;\
											background-color: #21BB21;\
											background: radial-gradient(#2BFD2B 10%,#1EB41E  55%, #30B530 80% , green);\
											box-shadow: 0px 0px 2px 1px #22C922;';
					var defaultButtonLabelCSS = 'position:absolute;\
												width:70%;\
												right:0%;\
												top:50%;\
												margin-top:-0.5em;\
												display:table-cell;\
												text-align:center;\
												vertical-align:middle;\
												';
					var helperElement = document.createElement('div');
					helperElement.innerHTML = that.HTMLBase;
					var newComponent=helperElement.firstChild.cloneNode(true);
					document.getElementById(that.containerID).appendChild(newComponent);
					newComponent = document.getElementById(that.id);
					newComponent.style.cssText+=defaultButtonCSS;
					var supportedCSSRules = that.getSupportedCSSRules();
					for (var ruleIndex in supportedCSSRules ){
						if(this.drawParams[supportedCSSRules[ruleIndex]]){
							newComponent.style.cssText+=(supportedCSSRules[ruleIndex]+':'
														+that.drawParams[supportedCSSRules[ruleIndex]]+';');
						}
					}
					document.getElementById(that.id+'_actualButton').style.cssText+=defaultActualButtonCSS;
					document.getElementById(that.id+'_buttonTop').style.cssText+=defaultButtonTopCSS;
					document.getElementById(that.id+'_buttonIndicator').style.cssText+=defaultButtonIndicatorCSS;
					document.getElementById(that.id+'_buttonLabel').style.cssText+=defaultButtonLabelCSS;
					if(that.drawParams.subType==="openFile"||that.drawParams.subType==="saveFile"||that.drawParams.noIndicator){
						var elementToRemove = document.getElementById(that.id+'_buttonIndicator');
						if(elementToRemove){
							elementToRemove.parentNode.removeChild(elementToRemove);
						}
						document.getElementById(that.id+'_buttonLabel').style.cssText+='\
																						right:15%;';
						if(that.drawParams.subType==="openFile"){
							var hiddenOpenFileButton = document.createElement('div');
							hiddenOpenFileButton.innerHTML = 
								'<input id="'+that.id+'_hiddenButton" type="file" accept="*/*" />';/* image/* */
							hiddenOpenFileButton = hiddenOpenFileButton.children[0].cloneNode();
							document.getElementById(that.id+'_buttonTop').appendChild(hiddenOpenFileButton).style.display="none";
						}
					}
					
					return newComponent;
				},
				drawParams:{
					width:"60px",
					height:"20px",
					top:undefined,
					bottom:undefined,
					left:undefined,
					right:undefined,
					label:'&nbsp;',
					placeHolder:undefined,
					subType:undefined,
					label:undefined
				},
				controlInterfaceBuilder: function(){
					var that = this;
					var isOff = true;
					var actualButton = document.getElementById(that.id+'_actualButton');
					var originalActualButtonCSS = clone(actualButton.style,{});
					var buttonIndicator = document.getElementById(that.id+'_buttonIndicator');
					var actualButton = document.getElementById(that.id+'_actualButton');
					var pressedActualButtonCSS = 'border:1px solid black;\
														box-shadow:0px 0px 1px 0px black inset';
					var originalButtonIndicatorCSS = buttonIndicator ? clone(buttonIndicator.style, {} ) : undefined;
					var originalActualButtonStyle = actualButton ? clone(actualButton.style,{}) : undefined;
					var defaultTurnedOffIndicatorCSS = 'background:#2F7F2F;\
														background: radial-gradient(  #2F7F2F 20%, #30B530 60% , green);\
														box-shadow:none;';
					var defaultTurnedOffActualButtonCSS = '';
					var getState = function(){
						return isOff ? "off" : "on" ;
					}
					var on = function(){
						isOff = false;
						actualButton.style.cssText += pressedActualButtonCSS;
						buttonIndicator ? buttonIndicator.style.cssText += originalButtonIndicatorCSS.cssText : '';
						if(that.drawParams.subType&&(that.drawParams.subType=="openFile")){
							document.getElementById(that.id+'_hiddenButton').click();
						}else if(typeof that.controlInterfaceParams.onPress === 'function'){
							that.controlInterfaceParams.onPress( getState() );
						}
					}
					var off = function(){
						var localOff = function(){
							isOff = true;
							buttonIndicator ? buttonIndicator.style.cssText+=defaultTurnedOffIndicatorCSS : '';
							//actualButton.style.cssText += originalActualButtonStyle.cssText;
							actualButton.style.cssText = originalActualButtonStyle.cssText;
						}
						if(that.drawParams.subType&&(that.drawParams.subType=="openFile")){
							document.getElementById(that.id+'_hiddenButton').click();
							setTimeout(localOff,300);
						}else{
							localOff();
						}
						if(typeof that.controlInterfaceParams.onPress === 'function'){
							that.controlInterfaceParams.onPress( getState() );
						}
					}
					off();
					if(that.drawParams.subType==="openFile"){
						document.getElementById(that.id+'_hiddenButton').onchange=function(event){
							if (typeof that.controlInterfaceParams.onChange === "function") {
								that.controlInterfaceParams.onChange(this.files[0]);//TODO Very Important! Why accessing files this way //Resolved - EPIM
							}
							//off();
						};
					}
					if(that.drawParams.subType=="saveFile"){
						document.getElementById(that.id+'_buttonTop').onchange=function(event){
							if (typeof that.controlInterfaceParams.onChange === "function") {
								that.controlInterfaceParams.onChange();//TODO pass appropriate parameters
							}
							off();
						};
					}
					var onMouseClick = function(){
						isOff ? on() : off();
					}
					
					var getState = function(){
						return isOff ? "off" : "on" ;
					}
					
					var buttonTop = document.getElementById(that.id+'_buttonTop');
					buttonTop.onclick = onMouseClick;
					return {
						on:on,
						off:off,
						getState:getState
					}
				},
				controlInterfaceParams:{
					onChange:undefined
				}
			},
			monitor:{
				drawMonitor:function(){
					var that = this;
					that.HTMLBase ='<div id="'+that.id+'">\
										<div id="'+that.id+'_monitorSocket">\
											<div id="'+that.id+'_actualMonitor">\
												<div id="'+that.id+'_monitorTop">\
												</div>\
											</div>\
										</div>\
									</div>';
					var defaultMonitorCSS = '\
											position:absolute;\
											min-height:10px;\
											min-width:10px;\
											font-size:0.8em;\
											';
					var defaultMonitorSocketCSS = '\
											position:absolute;\
											height:100%;\
											width:100%;\
											font-size:0.8em;\
											';
					var defaultActualMonitorCSS='\
												position:absolute;\
												height:100%;\
												width:100%;\
												top:0px;\
												bottom:0px;\
												border: 1px solid black;\
												background-color: #DBDFF3;\
												background: \
													repeating-linear-gradient(45deg, white, #DBDFF3);\
												border-radius: 3% 3% 3% 3%;\
												box-shadow: inset 0px 0px 4px 1px #A2A5B4,\
													0px 1px 1px 1px #222524;\
												font-weight: bold;\
												';
					var defaultMonitorTopCSS = '\
												position:absolute;\
												height:100%;\
												width:100%;\
												';
					var defaultMonitorCanvasCSS = '\
												position:absolute;\
												';
					var helperElement = document.createElement('div');
					helperElement.innerHTML = that.HTMLBase;
					var container = document.getElementById(that.containerID);
					container.appendChild(helperElement.firstChild.cloneNode(true));
					var monitor = document.getElementById(that.id);
					var monitorSocket = document.getElementById(that.id+'_monitorSocket');
					var actualMonitor = document.getElementById(that.id+'_actualMonitor');
					var monitorTop = document.getElementById(that.id+'_monitorTop');
					var monitorTopSize={};
					monitor.style.cssText+=defaultMonitorCSS;
					monitorSocket.style.cssText+=defaultMonitorSocketCSS;
					actualMonitor.style.cssText+=defaultActualMonitorCSS;
					monitorTop.style.cssText+=defaultMonitorTopCSS;
					var supportedCSSRules = that.getSupportedCSSRules();
					for (var ruleIndex in supportedCSSRules ){
						if(that.drawParams[supportedCSSRules[ruleIndex]]){
							monitor.style.cssText+=(supportedCSSRules[ruleIndex]+':'
														+that.drawParams[supportedCSSRules[ruleIndex]]+';');
						}
					}
					var computedStyle = window.getComputedStyle(monitorTop);
					monitorTopSize.width = parseFloat(computedStyle.width);
					monitorTopSize.height = parseFloat(computedStyle.height);
					helperElement = document.createElement('div');
					helperElement.innerHTML = '<canvas id="'+that.id+'_monitorCanvas" width="'+monitorTopSize.width+'px" height="'+monitorTopSize.height+'px"></canvas>';
					monitorTop.appendChild(helperElement.firstChild);
					var monitorCanvas = document.getElementById(that.id+'_monitorCanvas');
					monitorCanvas.style.cssText+=defaultMonitorCanvasCSS;
					return monitor;
				},
				drawParams:{
					width:undefined,
					height:undefined,
					top:undefined,
					bottom:undefined,
					left:undefined,
					right:undefined,
					splash:false
				},
				controlInterfaceBuilder: function(){
					var that = this;
					var controlInterfaceBuilderEncapsulatedProperties = {};
					var canvas = document.getElementById(that.id + '_monitorCanvas');
					controlInterfaceBuilderEncapsulatedProperties.canvas = document.getElementById(that.id + '_monitorCanvas');
					controlInterfaceBuilderEncapsulatedProperties.context = canvas.getContext('2d');
					var currentCoordinateSystem = {};
					var imagesBuffer = [];
					var imageIDs = [];
					var getFreeImageID = function(){
						var freeImageIDIndex = 0;
						for(;freeImageIDIndex<imageIDs.length;freeImageIDIndex++){
							if(!imageIDs[freeImageIDIndex]){
								imageIDs[freeImageIDIndex] = true;
								return freeImageIDIndex;
							}
						}
						imageIDs[imageIDs.length] = true;
						return imageIDs.length-1;
					}
					var freeAnImageID = function(id){
						if(imageIDs[id])imageIDs[id]=false;
					}
					var isImageIDFree = function(id){
						if(imageIDs[id]){
							return false;
						}else{
							return true;
						}
					}
					var eraseImage = function(image){//TODO To check if method is implemented OK
						image.helperElement.getParent().removeChild(image.helperElement);
						controlInterfaceBuilderEncapsulatedProperties.context.clearRect(image.xOffset,image.yOffset,image.width,image.height);
					}
					var showImage = function(imageId){//TODO To check if it is implemented OK
						var image;
						drawImage(image);
						image.hidden = false;
					}
					var getImage = function(imageId){
						if(imageId==='on top'){
							return imagesBuffer[imagesBuffer.length-1];
						}
						for(var index=0; index<imagesBuffer.length; index++){
							if(imagesBuffer[index].id === imageId) return imagesBuffer[index];
						}
						return null;
					};
					var ImageDataObject = function(width, height, uInt8ClampedArray){
						var localCanvas = document.createElement('canvas');
						localCanvas.width = width;
						localCanvas.height = height;//TODO see if setting width and height to canvas is necessary
						var imageData = localCanvas.getContext('2d').createImageData(width,height);
						if(uInt8ClampedArray){
							imageData.data.set(new Uint8ClampedArray(uInt8ClampedArray));
						}
						localCanvas = undefined;
						return imageData;
					};
					var getImageCopy = function(imageId){
						var copyImage = function(image){
							if(!image)return undefined;
							var copy = {};
							for (var property in image){
								if(image.hasOwnProperty(property)){
									if(typeof image[property] !== 'object' ){
											copy[property] = image[property];
									}else{ 
										switch( property ){
											case 'imageAsFileObject': {
												copy[property] = image[property].slice(0,image[property].size,"image/"+image.fileType);
												break;
											}
											case 'imageAsBlobObject':{
												copy[property] = image[property].slice(0,image[property].size,"image/"+image.fileType);
												break;
											}
											case 'imageData': {
												copy[property] = new ImageDataObject(image.imageData.width,image.imageData.height,image.imageData.data);
												break;
											}
											default: {
												copy[property] = image[property];
											}
										}
									}
								}
							}
							return copy;
						}
						if(imageId==='on top'){
							return copyImage(imagesBuffer[imagesBuffer.length-1]);
						}
						for(var index=0;index<imagesBuffer.length;index++){
							if(imagesBuffer[index].id===imageId) {
								return copyImage(imagesBuffer[index]);
							}
						}
						return null;
					}					
					var hideImage = function(image){//TODO not fully implemented
						eraseImage(image);
						image.hidden=true;
					}
					var spinImages = function(delayInMiliseconds, fadeAwayDelayInMiliseconds){
						
					}
					var applyToImage = function(imageId, data){
						var image = getImage(imageId);
						/*if(data[0]==undefined){
							return 0;
						}*/
						if(image&&data&&data[0]!=undefined){
							image.imageData.data.set(data);
							controlInterfaceBuilderEncapsulatedProperties.context.clearRect(0,0,controlInterfaceBuilderEncapsulatedProperties.canvas.width,controlInterfaceBuilderEncapsulatedProperties.canvas.height);
							controlInterfaceBuilderEncapsulatedProperties.context.putImageData(image.imageData, image.xOffset, image.yOffset);
							//TODO check to see if the problem with the blob creation is not actually belonging here
							return 1;
						}else{
							return 0;
						}
					}
					var addImage = function(imageAsFileObject){
						var imageWrapper = {
							id:getFreeImageID(),
							hidden:false,
							state:'not ready',
							imageAsFileObject:imageAsFileObject
						};
						drawImage(imageWrapper);
						return imageWrapper.id;
					}
					var addImageFromWrapper = function(imageWrapper){
						imageWrapper.id = getFreeImageID();//NOTE VERY IMPORTANT id is rewritten every time an image is added
						//TODO Check to see if it is not a good idea to have a unique image id obtained as for example something as "monitorId" + "imageId"
						imageWrapper.hidden = false;
						imageWrapper.state = 'not ready';
						if(!imageWrapper.imageAsFileObject && !imageWrapper.imageAsBlobObject){
							return null;
						}
						drawImage( imageWrapper );
						return imageWrapper.id;
					};
					var drawImage = function( imageWrapper ){
						var fileReader = new FileReader();
						fileReader.onloadend_backup = function(e){
							putImageToCanvas( e.currentTarget.result );
						};
						fileReader.onloadend = function(e){
							whenImageIsFullyLoadded(e.currentTarget.result, imageWrapper);
						};
						fileReader.readAsDataURL( imageWrapper.imageAsFileObject );
					};
					var whenImageIsFullyLoadded = function(imageDataOfTheLoadedImage, imageWrapper){
						putImageToCanvas(imageDataOfTheLoadedImage, imageWrapper);
						if( imageWrapper.state === 'not ready' ){
							imageWrapper.state = 'ready';
							imagesBuffer.push(imageWrapper);
							if(typeof that.controlInterfaceParams.onLoad==='function'){
								that.controlInterfaceParams.onLoad(imageWrapper);
							}
							return 1;
						}else{
							return 0;
						}
					};
					var putImageToCanvas = function(imageData, imageWrapper){
						var helperElement = document.createElement('img');
						var canvasComputedStyle = window.getComputedStyle(controlInterfaceBuilderEncapsulatedProperties.canvas);
						var imageAspectRatio;
						var xSpareDistance = 0;
						var ySpareDistance = 0;
						helperElement.src = imageData;
						//imageWrapper.data = helperElement;//TODO check to see if that assignment is OK
						imageWrapper.src = helperElement.src;
						if( !imageWrapper.imageAsBlobObject ){//TODO check to see if this property has any sense
							imageWrapper.fileType = imageWrapper.src.match(/data:image\/(.*)?;.*/)[1];
						}else{
							helperElement.width = imageWrapper.width;
							helperElement.height = imageWrapper.height;
							helperElement.type = 'image/'+imageWrapper.fileType;
						}
						imageAspectRatio = parseFloat(helperElement.width)/parseFloat(helperElement.height);
						helperElement.style.position='absolute';
						if(helperElement.width>helperElement.height){
							helperElement.width = parseFloat(canvasComputedStyle.width);
							helperElement.height = parseFloat(helperElement.width)*(1/imageAspectRatio);
							ySpareDistance = controlInterfaceBuilderEncapsulatedProperties.canvas.height-helperElement.height;
						}else{
							helperElement.height = parseFloat(canvasComputedStyle.height);
							helperElement.width = parseFloat(canvasComputedStyle.height)*imageAspectRatio;
							xSpareDistance = controlInterfaceBuilderEncapsulatedProperties.canvas.width-helperElement.width;
						}
						controlInterfaceBuilderEncapsulatedProperties.context.drawImage(helperElement,xSpareDistance/2,ySpareDistance/2,helperElement.width,helperElement.height);
						imageWrapper.imageData = controlInterfaceBuilderEncapsulatedProperties.context.getImageData(xSpareDistance/2,ySpareDistance/2,helperElement.width,helperElement.height);
						imageWrapper.xOffset = xSpareDistance/2;
						imageWrapper.yOffset = ySpareDistance/2;
						imageWrapper.width = helperElement.width;
						imageWrapper.height = helperElement.height;
						imageWrapper.helperElement = helperElement;
						return imageWrapper;
					};
					var removeImage = function(id){
						if( !isImageIDFree(id) ){
							var indexOfImageToSplice;
							for (var i=0;i<imagesBuffer.length;i++){
								if(imagesBuffer[i].id===id){
									indexOfImageToSplice = i;
									break;
								}
							}
							imagesBuffer.splice(indexOfImageToSplice, 1);
							freeAnImageID(id);
							redrawImageBuffer();
							return 1;
						}else{
							return 0;
						}
					};
					var clearMonitor = function(){
						controlInterfaceBuilderEncapsulatedProperties.context.clearRect(0,0,controlInterfaceBuilderEncapsulatedProperties.canvas.width,controlInterfaceBuilderEncapsulatedProperties.canvas.height);
						imageIDs = [];
						imagesBuffer = [];
					}
					var redrawImageBuffer = function(){
						controlInterfaceBuilderEncapsulatedProperties.context.clearRect(0,0,controlInterfaceBuilderEncapsulatedProperties.canvas.width,controlInterfaceBuilderEncapsulatedProperties.canvas.height);
						for(index=0;index<imagesBuffer.length;index++){
							if(imagesBuffer[index].hidden===false) drawImage(imagesBuffer[index]);
						}
					}
					var createCoordinateSystem = function(params){
						var defaultParams = {
							minAbscissaValue:undefined,
							maxAbsscissaValue:undefined,
							minOordinateValue:undefined,
							maxOordinateValue:undefined,
							divisionStepRightAbscissa:undefined,
							divisionStepLeftAbscissa:undefined,
							divisionStepUpOordinate:undefined,
							divisionStepDownOordinate:undefined,
							leftAbscissaLength:undefined,
							rightAbscissaLength:undefined,
							upOordinateLength:undefined,
							downOordinateLength:undefined,
							axesEndType:undefined,
							nPeriode:undefined,
							animate:false,
							symmetric:true,
							minValue:undefined,
							maxValue:undefined,
							step:undefined,
							divisions:undefined
						};
						var actualParams;
						function parseParams(params,defaultParams){
							var parsedParams = {};
							if(!params||!defaultParams)return parsedParams;
							for (var key in defaultParams){
								if(defaultParams.hasOwnProperty(key)){
									if(params[key]||params[key]===0){
										parsedParams[key] = params[key];
									}else{
										parsedParams[key] = defaultParams[key];
									}
								}
							}
							return parsedParams;
						}
						actualParams = parseParams(params,defaultParams);
						var drawCoordinateSystem = function(params){
							
						};
						var destroyCoordinateSystem = function(){
							
						}
						if(currentCoordinateSystem&&typeof(currentCoordinateSystem.destroy)==='function')currentCoordinateSystem.destroy();
						var CoordinateSystem = function(params){
							var descreteFunctionsIDs = [];
							var descreteFunctions = [];
							var id;var center;
							var getFreeDescreteFunctionID = function(){
								var suffixIndex = 0;
								for(var suffixIndex=0;suffixIndex<descreteFunctionsIDs.length;suffixIndex){
									if(descreteFunctionsIDs[suffixIndex]===false) return suffixIndex;
								}
								return descreteFunctionsIDs.length;
							};
							var init = function(params){
								id = getFreeDescreteFunctionID();
								descreteFunctionsIDs[id] = true;
							};
							init();
							return new function(params){
								var createDescreteFunction = function(){
									var id;
									var index;
									if(!params.data)return null;
									var valuesAsFlatArray = [];
									if(typeof params.data === "string"){
										valuesAsFlatArray = params.data.split(',');
										drawDescreteFunction(valuesAsFlatArray);
									}
									if(typeof params.data === "object"){
										if( tools.isArray(params) ){
											if( params.data.length === 0 )return null;
											if( tools.isArray(params.data[0]) ){
												for(index=0;index<params.data.length;index++){
													valuesAsFlatArray.push(params.data[index]);
												}
												drawDescreteFunction(valuesAsFlatArray);
											}else{
												for(index=0;index<params.data.length;index++){
													valuesAsFlatArray.push(params.data[index].x);
													valuesAsFlatArray.push(params.data[index].y);
												}
												drawDescreteFunction(valuesAsFlatArray);
											}
										}else{
											return null;
										}
									}
									return id;
								};
								var drawDescreteFunction = function(params){
									
								};
								var eraseDescretefunction = function(id){
								};
								var hideDescreteFunction = function(id){
								};
								var showDiscreteFunction = function(id){
								};
								var	redrawDiscreteFunction = function(id){
									
								};
								var toControlInterface = function(){
									return controlInterface;
								}
							}(params);
						}
						currentCoordinateSystem = new CoordinateSystem(actualParams);
						if(currentCoordinateSystem)drawCoordinateSystem(actualParams);
						return currentCoordinateSystem;
					}
					var createCoordinateSystem_backup = function(params){
						var coordinateSystemParams = params||{};
						switch(coordinateSystemParams.quadrant){
							case 'first':{
								break;
							}
							case 'second':{
								break;
							}
							case 'third':{
								break;	
							}
							case 'fourth':{
								break;
							}
							default:{
								coordinateSystemParams.divisionsX=16;
								coordinateSystemParams.divisionStepX=16;
								coordinateSystemParams.divisionsY=20;
								coordinateSystemParams.divisionStepY=30;
								coordinateSystemParams.scalesX=true;
								coordinateSystemParams.alternate=true;
								currentCoordinateSystem = createFullCoordinateSystem(coordinateSystemParams);
							}
						}
						coordinateSystem = true;
						return that.controlInterface;
					}
					var drawHorizontalScales = function(params){
						var rightDistance = maxValue;
					};
					var drawVerticalScales = function(canvasContext){
					};
					var createFullCoordinateSystem = function(params){
						var coordinateSystemCenter = {};
						var canvasComputedStyle = window.getComputedStyle(controlInterfaceBuilderEncapsulatedProperties.canvas);
						var relativeCenter = {};
						relativeCenter.width = parseFloat(canvasComputedStyle.width);
						relativeCenter.height = parseFloat(canvasComputedStyle.height);
						coordinateSystemCenter.x = parseFloat(canvasComputedStyle.width).toFixed(2)/2;
						coordinateSystemCenter.y = parseFloat(canvasComputedStyle.height).toFixed(2)/2;
						controlInterfaceBuilderEncapsulatedProperties.context.beginPath();
						controlInterfaceBuilderEncapsulatedProperties.context.strokeStyle = "#730000";
						controlInterfaceBuilderEncapsulatedProperties.context.moveTo(relativeCenter.width/2,0.02*relativeCenter.height);
						controlInterfaceBuilderEncapsulatedProperties.context.lineTo(relativeCenter.width/2,relativeCenter.height - 0.02*relativeCenter.height);
						controlInterfaceBuilderEncapsulatedProperties.context.moveTo(relativeCenter.width*0.02,relativeCenter.height/2);
						controlInterfaceBuilderEncapsulatedProperties.context.lineTo(relativeCenter.width-relativeCenter.width*0.02,relativeCenter.height/2);
						controlInterfaceBuilderEncapsulatedProperties.context.stroke();
						var scaleLength=6;
						var divisionIndex;
						var divisionDistance=relativeCenter.width*0.96/params.divisionsX;
						var scaleNumber;
						var leftLimitX = -params.divisionsX;
						var downLimitY = -params.divisionsY;
						var fontSize = parseInt(controlInterfaceBuilderEncapsulatedProperties.context.font);
						if(isNaN(fontSize))fontSize=divisionDistance;
						var singleUnitDistance = divisionDistance/params.divisionStepX;
						var alternateOffset=0;
						controlInterfaceBuilderEncapsulatedProperties.context.beginPath();
						controlInterfaceBuilderEncapsulatedProperties.context.moveTo(relativeCenter.width*0.02,relativeCenter.height/2);
						for(divisionIndex = 0;divisionIndex<=params.divisionsX*2;divisionIndex++){
							controlInterfaceBuilderEncapsulatedProperties.context.moveTo(relativeCenter.width*0.02+divisionIndex*divisionDistance,relativeCenter.height/2-scaleLength/2);
							controlInterfaceBuilderEncapsulatedProperties.context.lineTo(relativeCenter.width*0.02+divisionIndex*divisionDistance,relativeCenter.height/2+scaleLength/2);
						}
						controlInterfaceBuilderEncapsulatedProperties.context.stroke();
						controlInterfaceBuilderEncapsulatedProperties.context.beginPath();
						controlInterfaceBuilderEncapsulatedProperties.context.moveTo(relativeCenter.width/2,relativeCenter.height*0.02);
						divisionDistance = relativeCenter.height*0.96/params.divisionsY;
						controlInterfaceBuilderEncapsulatedProperties.context.moveTo(relativeCenter.width/2,relativeCenter.height*0.02);
						for(divisionIndex = 0;divisionIndex<=params.divisionsY;divisionIndex++){
							controlInterfaceBuilderEncapsulatedProperties.context.moveTo(relativeCenter.width/2-scaleLength/2,relativeCenter.height*0.02+divisionIndex*divisionDistance);
							controlInterfaceBuilderEncapsulatedProperties.context.lineTo(relativeCenter.width/2+scaleLength/2,relativeCenter.height*0.02+divisionIndex*divisionDistance);
						}
						controlInterfaceBuilderEncapsulatedProperties.context.stroke();
						controlInterfaceBuilderEncapsulatedProperties.context.beginPath();
						controlInterfaceBuilderEncapsulatedProperties.context.moveTo( relativeCenter.width/2, relativeCenter.height/2);
						controlInterfaceBuilderEncapsulatedProperties.context.textAlign = "left";
						controlInterfaceBuilderEncapsulatedProperties.context.strokeText('0',relativeCenter.width/2, relativeCenter.height/2+fontSize);
						controlInterfaceBuilderEncapsulatedProperties.context.textAlign = "center";
						for(divisionIndex=1;divisionIndex<params.divisionsX;divisionIndex++){
							if(params.alternate===true){
								alternateOffset === fontSize ? alternateOffset = 0 : alternateOffset = fontSize;
							}
							controlInterfaceBuilderEncapsulatedProperties.context.strokeText(''+divisionIndex*params.divisionStepX,
												relativeCenter.width/2+divisionIndex*params.divisionStepX,
												relativeCenter.height/2+fontSize+alternateOffset
												);
							
						}
						controlInterfaceBuilderEncapsulatedProperties.context.stroke();
						return {
							absoluteCenterX: relativeCenter.width/2,
							absoluteCenterY: relativeCenter.height/2
						};
					};
					var destroyCoordinateSystem = function(){
						coordinateSystem = false;
						currentCoordinateSystem = {};
						return that.controlInterface;
					};
					var controlInterface = {
						applyToImage:applyToImage,
						addImageFromWrapper:addImageFromWrapper,
						clearMonitor:clearMonitor,
						getImageCopy:getImageCopy,
						getImage:getImage,
						addImage: addImage,
						removeImage: removeImage,
						createCoordinateSystem: createCoordinateSystem
					};
					return controlInterface;
				},
				controlInterfaceParams:{
					onLoad:undefined,
					onDrop:undefined,
					onChange:undefined
				}
			}
		};
		var ComponentsDescriptor = function(typeObject){
			var IDsSuffixes = [];
			var componentsArray = [];
			var supportedCSSRules = ['width','height','top','left','bottom','right'];
			var getSupportedCSSRules = function(){
				return supportedCSSRules;
			}
			var component = {
				id:undefined,
				containerID:undefined,
				embedded:false,
				HTMLBase:undefined,
				type:typeObject.name,
				drawParams:clone(typeObject.defaultDrawParams,{}),
				draw:typeObject.defaultDraw,
				controlInterface:undefined,
				controlInterfaceBuilder:typeObject.defaultControlInterfaceBuilder,
				controlInterfaceParams:typeObject.defaultControlInterfaceParams,
				childs:[],
				parent:undefined,
				getSupportedCSSRules:getSupportedCSSRules,
			};
			var getMeAnIDSuffix = function(){
				for(var i = 0;i<IDsSuffixes.length;i++){
					if(IDsSuffixes[i]==false){
						IDsSuffixes[i]=true;
						return i;
					}
				}
				var indexOfNext = IDsSuffixes.length;
				IDsSuffixes.push(true);
				return indexOfNext;
			};
			var freeMeAnID = function(component){
				if(component.id){
					var idSuffix = component.id && component.id.match(/([0-9]*)$/)[0];
					IDsSuffixes[idSuffix] = false;
				}
			}
			var freeAnIDSuffix = function(index){
				IDsSuffixes[index] = false;
			}
			var getComponent = function(componentID){
				for (var index in componentsArray){
					if (componentsArray[index].id == componentID){
						return componentsArray[index];
					}
				}
				return undefined;
			};
			var checkIfContainerIsAComponent = function(containerID){
				var idPrefix = containerID.match(/(^[A-Za-z]*)/)[0];
				if(componentDescriptorsByType[idPrefix]){
					var allComponentsOfThisType = componentDescriptorsByType[idPrefix].getAllComponents();
					for (var componentIdx in allComponentsOfThisType){
						if(allComponentsOfThisType.hasOwnProperty(componentIdx)&&allComponentsOfThisType[componentIdx].id==containerID){
							return true;
						}
					}
				}
				return false;
			}
			var createComponent = function(params){
				var newComponent = clone(component,{});
				var defaultComponentDrawParams = clone(component.drawParams,{});
				var copyOfParamsDrawParams = clone(params.drawParams,{});
				if(!newComponent.controlInterfaceParams)newComponent.controlInterfaceParams = {};
				var suffix = getMeAnIDSuffix();
				var containerChilds = [];
				newComponent.id = ""+component.type+suffix;
				newComponent.containerID = params.containerID;
				newComponent.childs = [];
				if(checkIfContainerIsAComponent(params.containerID)){
					newComponent.parentID = params.containerID;
					containerChilds = that.getComponent(params.containerID).childs;
					if(containerChilds){
						containerChilds.push(newComponent.id);
					}else{
						containerChilds = [];
						containerChilds.push(newComponent.id);
					}
				}
				componentsArray.push(newComponent);
				if(params.drawParams){
					for (var drawParam in defaultComponentDrawParams){
						if(defaultComponentDrawParams.hasOwnProperty(drawParam)){//TODO debug the lines below
							if(params.drawParams[drawParam]||copyOfParamsDrawParams[drawParam]===0){
								newComponent.drawParams[drawParam] = copyOfParamsDrawParams[drawParam];
							}else{
								newComponent.drawParams[drawParam] = defaultComponentDrawParams[drawParam];
							}
						}
					}
				}else{
					newComponent.drawParams = defaultComponentDrawParams;
				}
				if(params.draw){
					newComponent.draw = params.draw;
					newComponent.draw();
				}else{
					newComponent.draw();
				}
				if(params.controlInterfaceBuilder){
					newComponent.controlInterfaceBuilder = params.controlInterfaceBuilder;
				}
				if(params.controlInterfaceParams){
					for (var controlParam in params.controlInterfaceParams){
						if(params.controlInterfaceParams.hasOwnProperty(controlParam)){
							if(params.controlInterfaceParams[controlParam]){
								newComponent.controlInterfaceParams[controlParam] = params.controlInterfaceParams[controlParam];
							}else{
								newComponent.controlInterfaceParams[controlParam] = component.controlInterfaceParams[controlParam];
							}
						}
					}
				}else{
					newComponent.controlInterfaceParams = clone(component.controlInterfaceParams,{});
				}
				newComponent.controlInterface = typeof newComponent.controlInterfaceBuilder == "function" ?
												newComponent.controlInterfaceBuilder(newComponent.controlInterfaceParams) : undefined;
				return newComponent;
			};
			var removeComponent = function(component){
				if(!component) return;//TODO see if I can add some error handling mechanism for the framework
				function removeChilds(component){
					for (childID in component.childs){
						removeComponent(getComponent(childID));
					}
				}(component);
				if( component.containerID ){
					var container = getComponent(component.containerID);//NOTE new debug
					if(container && container.childs){
						for (var i=0;i<container.childs.length;i++){
							if(container.childs[i]==component.id){
								container.childs = container.childs.slice(0,i)
													.concat(container.childs.slice(i+1,container.childs.length));
								break;
							}
						}
					}
					var childElementToRemove = document.getElementById(component.id);
					var parentElement = document.getElementById(component.containerID);
					if( childElementToRemove && parentElement ){
						parentElement.removeChild(
							childElementToRemove
						);
					}
				}
				for(var i=0;i<componentsArray.length;i++){
					if(componentsArray[i]==component.id){
						componentsArray = componentsArray.slice(0,i)
							.concat(componentsArray.slice(i+1,componentsArray.length));
						break;
					}
				}
				freeMeAnID(component);
				component = undefined;
			};
			var getAllComponents = function(){
				return componentsArray;
			};
			return {
				createComponent: createComponent,
				removeComponent: removeComponent,
				getComponent: getComponent,
				getAllComponents: getAllComponents
			};	
		};
		var types = {
			panel:{
				name:"panel",
				defaultDraw:defaultComponents.panel.drawPanel,
				defaultDrawParams:defaultComponents.panel.drawParams,
				defaultControlInterfaceBuilder: defaultComponents.panel.controlInterfaceBuilder
			},
			knob:{
				name:"knob",
				defaultDraw:defaultComponents.knob.drawKnob,
				defaultDrawParams:defaultComponents.knob.drawParams,
				defaultControlInterfaceBuilder:defaultComponents.knob.controlInterfaceBuilder,
				defaultControlInterfaceParams:defaultComponents.knob.controlInterfaceParams
			},
			display:{
				name:"display",
				defaultDraw:defaultComponents.display.drawDisplay,
				defaultDrawParams:defaultComponents.display.drawParams,
				defaultControlInterfaceBuilder: defaultComponents.display.controlInterfaceBuilder
			},
			label:{
				name:"label",
				defaultDraw:defaultComponents.label.drawLabel,
				defaultDrawParams:defaultComponents.label.drawParams,
				defaultControlInterfaceBuilder: defaultComponents.label.controlInterfaceBuilder
			},
			slider:{
				name:"slider",
				defaultDraw:defaultComponents.slider.drawSlider,
				defaultDrawParams:defaultComponents.slider.drawParams,
				defaultControlInterfaceBuilder: defaultComponents.slider.controlInterfaceBuilder,
				defaultControlInterfaceParams: defaultComponents.slider.controlInterfaceParams
			},
			button:{
				name:"button",
				defaultDraw:defaultComponents.button.drawButton,
				defaultDrawParams:defaultComponents.button.drawParams,
				defaultControlInterfaceBuilder:defaultComponents.button.controlInterfaceBuilder,
				defaultControlInterfaceParams:defaultComponents.button.controlInterfaceParams
			},
			monitor:{
				name:"monitor",
				defaultDraw:defaultComponents.monitor.drawMonitor,
				defaultDrawParams:defaultComponents.monitor.drawParams,
				defaultControlInterfaceBuilder:defaultComponents.monitor.controlInterfaceBuilder,
				defaultControlInterfaceParams:defaultComponents.monitor.controlInterfaceParams
			}
		};
		var addTypeOfComponents = this.addTypeOfComponents = function(typeObject){
			types[typeObject.name] = typeObject;
			componentDescriptorsByType[typeObject.name] = new ComponentsDescriptor(typeObject);
		};
		var removeTypeOfComponents = this.removeTypeOfComponents = function(typeName){
			delete types[typeName];
			for (var component in componentsByType[typeName].componentsArray){
				componentDescriptorsByType[typeName].removeComponent(componnet.id);
			}
			delete componentsByType[typeName];//TODO see if the old "type" index was OK
		};
		var componentDescriptorsByType = this.componentDescriptorsByType = function(){
			var componentDescriptorsByType = {};
			for (var k in types){
				if( types.hasOwnProperty(k) ){
					componentDescriptorsByType[k] = new ComponentsDescriptor(types[k]);
				}
			}
			return componentDescriptorsByType;
		}();
		var createComponent = this.createComponent = function(params){
			return componentDescriptorsByType[params.type].createComponent(params);
		}
		var removeComponent = this.removeComponent = function(component){
			var idPrefix = component.id.match(/(^[A-Za-z]*)/)[0];
			return componentDescriptorsByType[idPrefix].removeComponent(component);
		}
		var getListOfComponentTypes = this.getListOfComponentTypes = function(){
			var listOfTypes = [];
			for (var k in componentDescriptorsByTypes){
				if(componentDescriptorsByTypes.hasOwnProperty(k)){
					listOfTypes.push(k);
				}
			}
			return listOfTypes;
		}
		var getComponent = this.getComponent= function(componentID){
			var idPrefix = componentID.match(/(^[A-Za-z]*)/)[0];
			return componentDescriptorsByType[idPrefix].getComponent(componentID);
		}
	}
	this.tools = tools;
	this.componentManager = new ComponentManager();
}
